home *** CD-ROM | disk | FTP | other *** search
-
- (*
- * Modul-Skelett zur Verwaltung von System-Ressourcen
- * --------------------------------------------------
- * mit Hilfe von 'ResHandler'
- * --------------------------
- *
- * Das folgende Modul 'SysLibSkeleton' ist eine beispielhafte Implementation
- * für das Verwalten von Zugriffen, die eröffnet und wieder geschlossen
- * werden können. Die Module 'Files', 'Excepts' oder 'TextWindows' sind
- * diesbezüglich ähnlich aufgebaut.
- *
- * Problemstellung:
- * Beim Dateizugriff oder beim Verwenden mehrerer Fenster wird im
- * Allgemeinen ein Zugriff mit einer 'Open'-Funktion erlangt und am
- * Ende mit der entsprechenden 'Close'-Funktion wieder beendet.
- * Für dieses Verfahren gibt viele weitere Anwendungen, z.B. für
- * Module, die Stapel (Stacks), Schlangen (Queues) oder Verwenden
- * von Systemvektoren, wie Timer, VBL-Queue, usw., vorsehen.
- *
- * Im Allgemeinen ist es dabei wünschenswert, dem Anwenderprogramm
- * die Arbeit abzunehmen, beim Programmende alle eröffneten Zugriffe
- * wieder zu schließen. In der Regel sollte dies zwar am Ende des
- * Programms geschehen aber bei einem Laufzeitfehler oder einfach
- * schlampiger Programmierung sollte das betreffende Modul dies zur
- * Not selbst erledigen können.
- *
- * Man kann sich nun aber, vor Allem beim Megamax-System, Anwendungen
- * vorstellen, bei denen bei Programmende die Zugriffe erhalten bleiben
- * sollen, so z.B., wenn der Zugriff vom darunter liegenden Prozeß
- * weitergeführt werden soll oder wenn das Programm resident bleiben
- * will und weiterhin die Zugriffe benötigt.
- *
- * In den betroffenen MOS-Modulen sind deshalb, wie auch im Handbuch
- * in Kapitel 5.1, unter 'Allg. Hinweise zu den Modulen' vermerkt,
- * 'Sys'-Funktionen vorgesehen. Diese Funktionen dienen dazu, den Zugriff
- * so zu eröffnen, daß er nicht mehr automatisch geschlossen wird.
- * In dem Fall ist dann das Anwenderprogramm wieder ganz und gar selbst
- * für das Schließen verantwortlich.
- *
- * Die folgende Modulimplementation sieht nun alle Funktionen vor, um
- * sowohl das normale, automatische Schließen als auch die Sys-Funktion
- * korrekt durchzuführen. Das Definitionsmodul muß dazu immer zwei
- * 'Open'-Funktionen (wovon die eine mit 'Sys' beginnt) und eine Close-
- * Funktion enthalten. Weiterhin sind eigene Funktionen zum Zugriff auf
- * die 'Resourcen' implementierbar. Die Namensgebung ist selbstver-
- * ständlich beliebig, nur sollte die Sys-Funktion auf jeden Fall mit
- * diesem Prefix ("Sys") beginnen.
- *
- * Außerdem ist schon alles vorgesehen, wiederholte, verschiedene
- * Zugriffe zu verwalten, indem für jeden Zugriff ein Record angelegt
- * wird, in dem die spezifischen Daten stehen und alle solche Records
- * in einer Liste verkettet werden. Es ist unumgänglich, die Zugriffe
- * untereinander zu verketten, aber sie können natürlich auch anders
- * als mit einer Liste realisiert werden.
- *
- * Die Verwaltung geöffneter Zugriffe in Listen und das automatische
- * Schließen wird mit Hilfe des Moduls 'ResHandler' realisiert.
- *
- * Das Beispielmodul zeigt eine einfache Anwendung, bei der beim
- * Öffnen eines Zugriffs eine Zahl bestimmt werden kann. Mit der
- * Zugriffsfunktion 'DoIt' kann dann eine Textzeile ausgegeben werden,
- * die um soviel Zeichen eingerückt ist, wie vorher beim Öffnen bestimmt
- * wurde. Für dies einfache Beispiel findet sich ganz am Ende ein Modul,
- * das die Verwendung dieses Systemmoduls demonstiert. Diese gesamte
- * Textdatei kann auf einmal vom Compiler übersetzt werden und dann das
- * enthaltene Testmodul mit Ctrl-A von der Shell aus gestartet werden.
- *
- * Um eigene Systemmodule zu erstellen, sind die Namen im Definitions-
- * text und ggf. die Parameter bei den Open-Funktionen zu ändern und
- * eigene Zugriffsroutinen zu deklarieren. Im Implementationsteil müssen
- * die Zugriffsroutinen neu programmiert werden (anhand der Beispielrou-
- * tine 'DoIt') und in den Funktionen 'myOpen' und 'myClose' müssen ggf.
- * die externen Zugriffe initialisiert bzw. rückgesetzt werden. Außerdem
- * muß das Zugriffs-Record 'MyType' mit den benötigten Datenfeldern
- * versehen werden.
- *
- * Alle weiteren Änderungsstellen sind im Text mit drei Punkten im
- * Kommentar versehen. Die Kontrollausgaben sollten natürlich auch
- * entfernt werden.
- *)
-
-
- DEFINITION MODULE SysLibSkeleton;
-
- TYPE Handle;
-
- PROCEDURE OpenIt (VAR hdl: Handle; param: CARDINAL; VAR ok: BOOLEAN);
- (*
- * Öffnet einen Zugriff (Ressource).
- * 'param' bestimmt dabei die Einrückungsweite (s. 'DoIt').
- * Bei Prozeßende wird der Zugriff automatisch geschlossen
- *)
-
- PROCEDURE SysOpenIt (VAR hdl: Handle; param: CARDINAL; VAR ok: BOOLEAN);
- (*
- * Wie 'OpenIt', jedoch als 'Sys'-Funktion (siehe Handbuch, Kap. 5.1)
- * Bei Prozeßende wird der Zugriff NICHT automatisch geschlossen, sondern
- * muß manuell vom anwendenden Programm geschlossen werden!
- *)
-
- PROCEDURE DoIt (hdl: Handle; data: ARRAY OF CHAR; VAR ok: BOOLEAN);
- (*
- * Gibt Textzeile aus, eingerückt um den Wert, der beim Öffnen des
- * Zugriffs f. 'hdl' angegeben wurde.
- *)
-
- PROCEDURE CloseIt (VAR hdl: Handle);
- (*
- * Beendet Zugriff auf 'hdl'
- *)
-
- END SysLibSkeleton.
-
- (* ----------------------------------------------------------------------- *)
-
- IMPLEMENTATION MODULE SysLibSkeleton;
-
- (*$Y+ Kennzeichnung für Systemmodule mit "shared data" (s. Handbuch) *)
-
- FROM SYSTEM IMPORT ADDRESS, ADR;
- FROM Storage IMPORT SysAlloc, DEALLOCATE;
- FROM ErrBase IMPORT RtnCond, ErrResp, RaiseError;
- FROM MOSGlobals IMPORT OutOfMemory;
- FROM ResHandler IMPORT Resource, CreateResource,
- InsertHandle, InsertSysHandle,
- RemoveHandle, HandleInList;
-
- (* ... werden ggf. nicht benötigt: *)
- IMPORT TOSIO, InOut, Strings;
-
-
- TYPE MyType = RECORD
- (* ... hier folgen die eigenen Datenfelder: *)
- col: CARDINAL;
- END;
-
- TYPE Handle = POINTER TO MyType; (* Der Opaque Typ wird redeklariert *)
-
- VAR HandleList: Resource; (* Liste zum Verketten der Zugriffe *)
-
-
- PROCEDURE myClose (hdlAddr: ADDRESS; user: BOOLEAN);
- (*
- * Diese Prozedur übernimmt das Schließen eines Zugriffs und wird
- * bei '(Sys)InsertHandle' als Parameter für die Freigabeprozedur
- * übergeben.
- *)
- VAR hdl: Handle;
- BEGIN
- hdl:= hdlAddr; (* Initialisierung (Typkonvertierung) *)
- WITH hdl^ DO
- (* ... hier müssen ggf. Rücksetzungen erfolgen, wie *)
- (* z.B. veränderte Vektoren wiederherzustellen. *)
- IF user THEN
- InOut.WriteString( 'Der Benutzer ');
- ELSE
- InOut.WriteString( 'Das System ');
- END;
- InOut.WriteString ('schließt den Zugriff auf Spalte ');
- InOut.WriteCard (col, 0);
- InOut.WriteLn;
- END;
- DEALLOCATE (hdl, 0) (* Speicher f. Record freigeben *)
- END myClose;
-
- PROCEDURE myOpen ( VAR hdl : Handle;
- param : CARDINAL;
- VAR ok : BOOLEAN;
- sysLevel: BOOLEAN);
- (*
- * Ist sysLevel 'TRUE', dann wird der Zugriff bei Prozessende nicht
- * automatisch geschlossen.
- *)
- VAR strOk, found, error: BOOLEAN;
- BEGIN
- ok:= FALSE;
- (* Nur neu öffnen, wenn Zugriff noch nicht geöffnet ist: *)
- IF NOT HandleInList (HandleList, hdl) THEN
- (*
- * Nun Speicher für Record anfordern. Dazu wird eine 'Sys'-Funktion
- * benutzt (wichtig!!), damit dieser auch 'InsertSysHandle' überlebt.
- * Auch, wenn andere Ressourcen (GEM, Vektoren, Prozesse, usw.) hier
- * angelegt werden, sollten möglichst immer 'Sys'-Funktion dazu ver-
- * wendet werden. Ist dies nicht möglich, darf hier auch keine Sys-
- * Funktion angeboten werden, damit's nicht schiefgeht!
- * Natürlich kann dieses Modul auch Dinge tun, wozu überhaupt keine
- * externen Ressourcen (wie der Speicher für das Record) geöffnet werden
- * müssen, z.B. wenn hier nur damit ein Daten-Stack aufgebaut wird.
- * Dann kann hier natürlich problemlos eine Sys-Funktion angeboten
- * werden.
- *)
- SysAlloc (hdl, SIZE (hdl^));
- IF hdl # NIL THEN
- (* Record in der Resource-Liste HandleList verketten *)
- IF sysLevel THEN
- (* System-Zugriff; nur verwenden, wenn der Rest (Speicher, usw.)
- * auch mit Sys-Funktionen angelegt wurde! *)
- InsertSysHandle (HandleList, hdl, myClose, error);
- ELSE
- (* normaler Zugriff *)
- InsertHandle (HandleList, hdl, myClose, error);
- END;
- IF error THEN
- DEALLOCATE (hdl, 0)
- ELSE
- WITH hdl^ DO
- (* ... hier folgen eigene Initialisierungen *)
- (* ... und Zuweisungen der Record-Felder: *)
- col:= param;
- END;
- ok:= TRUE
- END
- END
- END
- END myOpen;
-
- PROCEDURE OpenIt (VAR hdl: Handle; param: CARDINAL; VAR ok: BOOLEAN);
- (*
- * Normales Eröffnen eines Zugriffs (einer Ressource).
- *)
- BEGIN
- myOpen (hdl, param, ok, FALSE)
- END OpenIt;
-
- PROCEDURE SysOpenIt (VAR hdl: Handle; param: CARDINAL; VAR ok: BOOLEAN);
- (*
- * Dauerhaftes Eröffnen eines Zugriffs (einer Ressource).
- *)
- BEGIN
- myOpen (hdl, param, ok, TRUE)
- END SysOpenIt;
-
-
- PROCEDURE DoIt (hdl: Handle; data: ARRAY OF CHAR; VAR ok: BOOLEAN);
- (*
- * Operation auf dem Zugriff (auf der Ressource)
- *)
- BEGIN
- (* Existiert Zugriff überhaupt ? *)
- IF HandleInList (HandleList, hdl) THEN
- WITH hdl^ DO (* ja, dann ist der 'handle' gültig. *)
- (* ...hier wird ein Zugriff durchgeführt: *)
- InOut.WriteString (Strings.Space (col)); (* 'col' aus Record *)
- InOut.WriteString (data);
- InOut.WriteLn;
- END
- END
- END DoIt;
-
-
- PROCEDURE CloseIt (VAR hdl: Handle);
- BEGIN
- (*
- * Falls der angegebene Zugriff noch existiert, wird der
- * belegte Speicher freigegeben und der Zugriff aus der Liste
- * 'HandleList' gelöscht.
- *)
- RemoveHandle (HandleList, hdl)
- END CloseIt;
-
-
- VAR error: BOOLEAN;
-
- BEGIN
- CreateResource (HandleList, error);
- IF error THEN
- RaiseError (OutOfMemory, '', selfCaused, mustAbort)
- END;
- END SysLibSkeleton.
-
- (* ----------------------------------------------------------------------- *)
-
- MODULE SysLibDemo;
-
- (*
- * Dies Modul demonstiert die Anwendung des obigen Beispielmoduls.
- *
- * Es öffnet erst zwei Zugriffe, dann wendet es die Zugriffsfunktionen an,
- * dann startet es einen Tochterprozeß, welcher ebenfalls zwei Zugriffe
- * eröffnet. Einer der Zugriffe wird mit der Sys-Funktion geöffnet. Der
- * Prozeß gibt auch mit 'DoIt' Text aus und endet dann, ohne die Zugriffe
- * zu schließen. Der eine Zugriff wird sodann vom Systemmodul geschlossen,
- * während der Sys-Zugriff erhalten bleibt. Dann werden im ersten Prozeß
- * wieder Ausgaben mit 'DoIt' gemacht, wobei auch der noch vorhandene
- * Sys-Zugriff benutzt wird. Am Ende wird dann einer der beiden ersten
- * Zugriffe ordnungsgemäß geschlossen, sodaß das Systemmodul den anderen
- * wiederum automatisch schließt.
- *
- * Der Sys-Zugriff muß (immer) explizit geschlossen werden, was in der
- * 'Termination'-Funktion geschieht, die zuvor mit 'CatchProcessTerm'
- * einen Aufruf bei Prozeßende angefordert hat. Dies ist besser, als am
- * Ende des Programmtextes diesen Aufruf durchzuführen, weil bei einem
- * Laufzeitfehler diese Programmstelle nicht mehr erreicht werden würde
- * und der Zugriff für immer (bis zum Reset des Rechners) als "Leiche"
- * im Speicher verleiben würde.
- *
- * Die Fehlerabfragen ('ok') wurden absichtlich weggelassen, da hier sowieso
- * alles funktionieren sollte (Speicher sollte ausreichen).
- *)
-
- IMPORT GEMDOSIO; (*$E MOS ..machen wir ein TOS-Programm draus. *)
-
- FROM SYSTEM IMPORT ADR;
- FROM SysLibSkeleton IMPORT Handle, OpenIt, SysOpenIt, DoIt, CloseIt;
- FROM MOSGlobals IMPORT MemArea;
- FROM ModCtrl IMPORT CallProcess;
- FROM ResCtrl IMPORT CatchRemoval, RemovalCarrier;
- FROM PrgCtrl IMPORT CatchProcessTerm, TermCarrier;
- IMPORT InOut;
-
- MODULE local;
-
- (*
- * Dies lokale Modul enthält eine Prozedur, die als neuer Prozeß unter
- * dem Hauptprogramm gestartet wird.
- * Ebenso könnte zur Demonstration mit 'Loader.CallModule' ein anderes
- * Modul als Tochterprozeß gestartet werden, das dann 'SysLibSkeleton'
- * importiert und die im Folgenden gezeigten Funktionen aufruft.
- *)
-
- IMPORT Handle, OpenIt, SysOpenIt, DoIt, CloseIt;
- IMPORT InOut;
-
- EXPORT otherProgram, sysHdl;
-
- VAR sysHdl: Handle;
-
- PROCEDURE otherProgram;
- VAR ok: BOOLEAN;
- hdl: Handle;
- BEGIN
- (* Normalen Zugriff zu diesem Prozeß öffnen *)
- OpenIt (hdl, 12, ok);
- InOut.WriteString ('Öffne Zugriff auf Spalte 12');
- InOut.WriteLn;
-
- (* Dauerhaften Zugriff öffnen *)
- SysOpenIt (sysHdl, 14, ok);
- InOut.WriteString ('Öffne Sys-Zugriff 2 auf Spalte 14');
- InOut.WriteLn;
-
- DoIt (hdl, 'Dies ist 2. Prozeß, normaler Zugriff', ok);
- DoIt (sysHdl, 'Dies ist 2. Prozeß, Sys-Zugriff', ok)
-
- (* Der Sys-Zugriff soll nicht geschlossen werden, da im *)
- (* Vaterprozeß noch darauf zugegriffen werden wird.. *)
- (* Der andere Prozeß wird einfach vergessen - er wird *)
- (* vom Systemmodul geschlossen werden. *)
- END otherProgram;
-
- END local;
-
- PROCEDURE Removal;
- VAR wait: CHAR;
- BEGIN
- InOut.WriteLn;
- InOut.WriteString ('Taste...');
- InOut.Read (wait);
- END Removal;
-
- PROCEDURE Termination;
- VAR wait: CHAR;
- BEGIN
- (* Der Sys-Zugriff muß spätestens hier geschlossen werden, sonst bleibt
- * er für immer geöffnet (und belegt damit unnötig Speicher). *)
- InOut.WriteString ('Schließe manuell Sys-Zugriff auf Spalte 14:');
- InOut.WriteLn;
- CloseIt (sysHdl);
- InOut.WriteLn;
- (* ... hier könnten eigene Ressourcen geschlossen werden. *)
- END Termination;
-
- VAR ok: BOOLEAN;
- exitCode: INTEGER; (* Exit-Code von 2. Prozeß *)
- stack: ARRAY [1..4096] OF CARDINAL; (* Stack für 2. Prozeß: 8 KB *)
- wsp: MemArea;
- rCarrier: RemovalCarrier;
- tCarrier: TermCarrier;
-
- hdl: ARRAY [1..2] OF Handle; (* 'Handles' für zwei Zugriffe *)
-
- BEGIN
- (* Bei Programmende soll 'Removal' aufgerufen werden, um auf einen
- * Tastendruck zu warten: *)
- wsp.bottom:= NIL; (* Damit wird der Stack des Hauptprozesses benutzt *)
- CatchRemoval (rCarrier, Removal, wsp);
-
- (* Bei Prozeßende soll 'Termination' aufgerufen werden *)
- wsp.bottom:= NIL; (* Damit wird der Stack des Hauptprozesses benutzt *)
- CatchProcessTerm ( tCarrier, Termination, wsp );
- (* Hier hätte auch 'CatchRemoval' verwendet werden *)
- (* können, da dies beim Hauptmodul, sofern es nicht *)
- (* resident ist, keinen Unterschied macht. *)
-
- (* Ersten Zugriff öffnen *)
- OpenIt (hdl [1], 2, ok);
- InOut.WriteString ('Öffne Zugriff 1 auf Spalte 2');
- InOut.WriteLn;
- (* Zweiten Zugriff öffnen *)
- OpenIt (hdl [2], 4, ok);
- InOut.WriteString ('Öffne Zugriff 2 auf Spalte 4');
- InOut.WriteLn;
-
- (* Funktionen auf die beiden Zugriffe durchführen *)
- DoIt (hdl [1], 'Dies ist 1. Prozeß, Zugriff 1', ok);
- DoIt (hdl [2], 'Dies ist 1. Prozeß, Zugriff 2', ok);
-
- (* Tochterprozeß starten *)
- InOut.WriteLn;
- wsp.bottom:= ADR (stack);
- wsp.length:= SIZE (stack);
- CallProcess (otherProgram, wsp, ok, exitCode);
- InOut.WriteLn;
-
- (* Funktionen auf die beiden Zugriffe dieses Prozesses und des *)
- (* residenten, vom Tochterprozeß geöffneten, Zugriffs durchführen *)
- DoIt (hdl [2], 'Dies ist wieder 1. Prozeß, Zugriff 2', ok);
- DoIt (hdl [1], 'Dies ist wieder 1. Prozeß, Zugriff 1', ok);
- DoIt (sysHdl, 'Dies ist der Sys-Zugriff', ok);
-
- (* Einen der hier geöffneten Zugriffe selber schließen, *)
- (* der andere wird testweise vom Systemmodul geschlossen *)
- InOut.WriteLn;
- InOut.WriteString ('Schließe manuell Zugriff 2 auf Spalte 4:');
- InOut.WriteLn;
- CloseIt (hdl [2]);
-
- InOut.WriteLn
-
- END SysLibDemo.
-